﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;

namespace CPS1
{
    // okno tworzenia sygnałów
    public partial class CreatorWindow : Form
    {
        private MainWindow parent; // uchwyt do głównego okna
        private Signal generatedSignal; // obiekt wygenerowanego sygnału

        public CreatorWindow(MainWindow parent)
        {
            InitializeComponent();

            this.parent = parent;
            // dezaktywacja pól gdy nie ma wczytanych żadnych sygnałó
            if (this.parent.loaded_signals.Count < 1)
            {
                label_error.Visible = true;
                cb_first_signal.Enabled = false;
                cb_second_signal.Enabled = false;
                cb_operation.Enabled = false;
                btn_o_create_save.Enabled = false;
            }
            else
            {
                for (int i = 0; i < this.parent.loaded_signals.Count; i++)
                {
                    cb_first_signal.Items.Add(this.parent.loaded_signals[i].name);
                    cb_second_signal.Items.Add(this.parent.loaded_signals[i].name);
                }
            }
        }
        // wybór pól - aktywacja konkretnych pól formularza
        private void cb_sygnal_TextChanged(object sender, EventArgs e)
        {
            switch (cb_sygnal.SelectedIndex) 
            {
                case 0: this.set_fields(new Boolean[]{ true, true, true, false, false, false, false, false, true, false }); break;
                case 1: this.set_fields(new Boolean[] { true, true, true, false, false, false, false, false, true, false }); break;
                case 2: this.set_fields(new Boolean[] { true, true, true, true, false, false, false, false, true, false }); break;
                case 3: this.set_fields(new Boolean[] { true, true, true, true, false, false, false, false, true, false }); break;
                case 4: this.set_fields(new Boolean[] { true, true, true, true, false, false, false, false, true, false }); break;
                case 5: this.set_fields(new Boolean[] { true, true, true, true, true, false, false, false, true, false }); break;
                case 6: this.set_fields(new Boolean[] { true, true, true, true, true, false, false, false, true, false }); break;
                case 7: this.set_fields(new Boolean[] { true, true, true, true, true, false, false, false, true, false }); break;
                case 8: this.set_fields(new Boolean[] { true, true, true, false, false, true, false, false, true, false }); break;
                case 9: this.set_fields(new Boolean[] { true, false, true, false, false, false, true, true, true, false }); break;
                case 10: this.set_fields(new Boolean[] { true, true, true, false, false, false, false, false, true, true }); break;
                default: this.set_fields(new Boolean[] { false, false, false, false, false, false, false, false, false, false }); ; break;
            }
        }
        // funkcja aktywująca konkretne pola formularza
        private void set_fields(Boolean[] fields)
        {
            tb_amplituda.Enabled = fields[0];
            tb_czas_poczatkowy.Enabled = fields[1];
            tb_czas_trwania_sygnalu.Enabled = fields[2];
            tb_okres_podstawowy.Enabled = fields[3];
            tb_wspolczynnik_wypelnienia.Enabled = fields[4];
            tb_czas_skoku.Enabled = fields[5];
            tb_numer_pierwszej_probki.Enabled = fields[6];
            tb_numer_probki_skoku.Enabled = fields[7];
            tb_czestotliwosc_probkowania.Enabled = fields[8];
            tb_prawdopodobienstwo_wystapienia_a.Enabled = fields[9];
        }
        // dodanie sygnału do listy
        private void addSignalToList(String signalName)
        {
            // wygenerowanie sygnału

            if (cb_sygnal.SelectedIndex == 0) this.generatedSignal = new UniformNoise(Double.Parse(tb_amplituda.Text), Double.Parse(tb_czas_poczatkowy.Text), Double.Parse(tb_czas_trwania_sygnalu.Text), Double.Parse(tb_czestotliwosc_probkowania.Text), signalName);

            if (cb_sygnal.SelectedIndex == 1) this.generatedSignal = new GaussianNoise(Double.Parse(tb_amplituda.Text), Double.Parse(tb_czas_poczatkowy.Text), Double.Parse(tb_czas_trwania_sygnalu.Text), Double.Parse(tb_czestotliwosc_probkowania.Text), signalName);

            if (cb_sygnal.SelectedIndex == 2) this.generatedSignal = new SinSignal(Double.Parse(tb_amplituda.Text), Double.Parse(tb_okres_podstawowy.Text), Double.Parse(tb_czas_poczatkowy.Text), Double.Parse(tb_czas_trwania_sygnalu.Text), Double.Parse(tb_czestotliwosc_probkowania.Text), signalName);

            if (cb_sygnal.SelectedIndex == 3) this.generatedSignal = new SinSOSignal(Double.Parse(tb_amplituda.Text), Double.Parse(tb_okres_podstawowy.Text), Double.Parse(tb_czas_poczatkowy.Text), Double.Parse(tb_czas_trwania_sygnalu.Text), Double.Parse(tb_czestotliwosc_probkowania.Text), signalName);

            if (cb_sygnal.SelectedIndex == 4) this.generatedSignal = new SinSDSignal(Double.Parse(tb_amplituda.Text), Double.Parse(tb_okres_podstawowy.Text), Double.Parse(tb_czas_poczatkowy.Text), Double.Parse(tb_czas_trwania_sygnalu.Text), Double.Parse(tb_czestotliwosc_probkowania.Text), signalName);

            if (cb_sygnal.SelectedIndex == 5) this.generatedSignal = new RectangularSignal(Double.Parse(tb_amplituda.Text), Double.Parse(tb_okres_podstawowy.Text), Double.Parse(tb_czas_poczatkowy.Text), Double.Parse(tb_czas_trwania_sygnalu.Text), Double.Parse(tb_wspolczynnik_wypelnienia.Text), Double.Parse(tb_czestotliwosc_probkowania.Text), signalName);

            if (cb_sygnal.SelectedIndex == 6) this.generatedSignal = new RectangularSymmetricSignal(Double.Parse(tb_amplituda.Text), Double.Parse(tb_okres_podstawowy.Text), Double.Parse(tb_czas_poczatkowy.Text), Double.Parse(tb_czas_trwania_sygnalu.Text), Double.Parse(tb_wspolczynnik_wypelnienia.Text), Double.Parse(tb_czestotliwosc_probkowania.Text), signalName);

            if (cb_sygnal.SelectedIndex == 7) this.generatedSignal = new TriangularSignal(Double.Parse(tb_amplituda.Text), Double.Parse(tb_okres_podstawowy.Text), Double.Parse(tb_czas_poczatkowy.Text), Double.Parse(tb_czas_trwania_sygnalu.Text), Double.Parse(tb_wspolczynnik_wypelnienia.Text), Double.Parse(tb_czestotliwosc_probkowania.Text), signalName);

            if (cb_sygnal.SelectedIndex == 8) this.generatedSignal = new VaultSignal(Double.Parse(tb_amplituda.Text), Double.Parse(tb_czas_poczatkowy.Text), Double.Parse(tb_czas_skoku.Text), Double.Parse(tb_czas_trwania_sygnalu.Text), Double.Parse(tb_czestotliwosc_probkowania.Text), signalName);

            if (cb_sygnal.SelectedIndex == 9) this.generatedSignal = new ImpulseSignal(Double.Parse(tb_amplituda.Text), Double.Parse(tb_numer_pierwszej_probki.Text), Double.Parse(tb_numer_probki_skoku.Text), Double.Parse(tb_czas_trwania_sygnalu.Text), Double.Parse(tb_czestotliwosc_probkowania.Text), signalName);

            if (cb_sygnal.SelectedIndex == 10) this.generatedSignal = new ImpulseNoise(Double.Parse(tb_amplituda.Text), Double.Parse(tb_czas_poczatkowy.Text), Double.Parse(tb_czas_trwania_sygnalu.Text), Double.Parse(tb_prawdopodobienstwo_wystapienia_a.Text), Double.Parse(tb_czestotliwosc_probkowania.Text), signalName); 

            // dodanie go do listy widocznej jako kontrolka i listy w pamięci
            this.parent.lb_signals_list.Items.Add(signalName + " ( " + tb_czestotliwosc_probkowania.Text + "Hz )");
            this.parent.loaded_signals.Add(this.generatedSignal.copy());
        }
        // zapis sygbału
        private void btn_wygeneruj_zapisz_Click(object sender, EventArgs e)
        {
            this.saveFileDialog1.Filter = "Plik sygnału|*.sign";
            this.saveFileDialog1.Title = "Zapisywanie sygnału";
            this.saveFileDialog1.ShowDialog();

            if(this.saveFileDialog1.FileName != "")
            {
                this.addSignalToList(this.saveFileDialog1.FileName);

                FileStream stream = new FileStream(this.saveFileDialog1.FileName, FileMode.Create);
                BinaryWriter writer = new BinaryWriter(stream);
                
                writer.Write("REAL"); // rodzaj wartości: REAL | COMPLEX

                // amplituda
                writer.Write(this.generatedSignal.A);

                // częstotliwość próbkowania
                writer.Write(this.generatedSignal.f);
                
                // czas początkowy
                writer.Write(this.generatedSignal.t1);

                // wartości amplitud
                double amountOfData = this.generatedSignal.d * this.generatedSignal.f;
                writer.Write(amountOfData);
                Double i = this.generatedSignal.t1;
                while (i < this.generatedSignal.t1 + this.generatedSignal.d)
                {
                    writer.Write((double)this.generatedSignal.value(i));
                    i = Math.Round(i + ((double)1.0 / (double)this.generatedSignal.f), 6);
                }
                // koniec zapisu
                writer.Close();
                // zamknięcie okna
                this.Close();
            }
        }
        // zapis sygnału z operacji
        private void btn_o_create_save_Click(object sender, EventArgs e)
        {
            // sprawdzenie poprawności wypełnienia formularza
            if (cb_first_signal.SelectedIndex != -1 && cb_second_signal.SelectedIndex != -1)
            {
                if (cb_operation.SelectedIndex != -1)
                {
                    if (this.parent.loaded_signals.ElementAt(cb_first_signal.SelectedIndex).f ==
                        this.parent.loaded_signals.ElementAt(cb_second_signal.SelectedIndex).f)
                    {
                        DiscreetSignal result = new DiscreetSignal("", 0, 0, 0, new Double[1,2]); //dorzucilam 0 na A ale nie wiem czy tak ma byc

                        // wybór operacji
                        char op;
                        if (cb_operation.SelectedIndex == 0) op = '+'; // dodawanie
                        else if (cb_operation.SelectedIndex == 1) op = '-'; // odejmowanie
                        else if (cb_operation.SelectedIndex == 2) op = '*'; // mnożenie
                        else op = '/'; // dzielenie

                        result = SignalOperations.operation(this.parent.loaded_signals.ElementAt(cb_first_signal.SelectedIndex), this.parent.loaded_signals.ElementAt(cb_second_signal.SelectedIndex), op);

                        // zapis do pliku
                        this.saveFileDialog1.Filter = "Plik sygnału|*.sign";
                        this.saveFileDialog1.Title = "Zapisywanie wynikowego sygnału";
                        this.saveFileDialog1.ShowDialog();

                        if (this.saveFileDialog1.FileName != "")
                        {
                            result.name = this.saveFileDialog1.FileName;
                            FileStream stream = new FileStream(this.saveFileDialog1.FileName, FileMode.Create);
                            BinaryWriter writer = new BinaryWriter(stream);

                            writer.Write("REAL"); // rodzaj wartości: REAL | COMPLEX
                            writer.Write(result.f); // częstotliwość próbkowania

                            // czas początkowy
                            writer.Write(result.t1);

                            // wartości amplitud
                            double amountOfData = result.calculatedValues.Length / 2;
                            writer.Write(amountOfData);
                            for (int i = 0; i < amountOfData; i++)
                            {
                                writer.Write((double)result.calculatedValues[i, 1]);
                            }
                            // koniec zapisu
                            writer.Close();

                            this.parent.lb_signals_list.Items.Add(result.name + " ( " + result.f + "Hz )");
                            this.parent.loaded_signals.Add(result.copy());

                            // zamknięcie okna
                            this.Close();
                        }
                    }
                    else
                    {
                        MessageBox.Show("Wybrane sygnały mają różne częstotliwości próbkowania. Proszę wybrać sygnały o takich samych częstotliwościach próbkowania");
                    }
                }
                else
                {
                    MessageBox.Show("Proszę wybrać rodzaj operacji do wykonania");
                }
            }
            else
            {
                MessageBox.Show("Proszę wybrać dwa sygnały do operacji");
            }
        }
    }
}
